#pragma once
#include "Sock.hpp"
#include "log.hpp"
#include "loop_epollserver.hpp"
#include "epoll.hpp"
#include "Common.hpp"
#include "Connection.hpp"
#include <memory>
#include <queue>
#include <unordered_map>

using func_t = std::function<std::string(std::shared_ptr<Connection>)>;

class Loop_Epollserver : public std::enable_shared_from_this<Loop_Epollserver>
{
    static const int array_num_max = 100;

public:
    Loop_Epollserver(uint16_t port, func_t OnMessage)
        : _port(port),
          _OnMessage(OnMessage),
          _sock_ptr(new Sock),
          _epoll_ptr(new Epoll)
    {
    }

    void Init()
    {

        // 1. 创建套接字
        // 2. 绑定
        // 3. 设置为监听模式
        // 4. 创建套接字对应二点Connection

        _sock_ptr->Socket();
        _sock_ptr->Bind(_port);
        _sock_ptr->Listen();

        int listensock = _sock_ptr->Get_fd();
        SetNonBlock(listensock);
        // 先将套接字加入到epoll中的红黑树中
        _epoll_ptr->add(listensock, EPOLLIN);

        // std::shared_ptr<Connection> shptr =

        _connects.emplace(listensock,
                          std::make_shared<Connection>(listensock, shared_from_this(),
                                                       std::bind(&Loop_Epollserver::Accept, this, std::placeholders::_1),
                                                       nullptr, nullptr));

        int opt = 1;
        setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
    }

    void Accept(std::shared_ptr<Connection> con_ptr)
    {
        // 接受一个新的文件描述符
        // 1. 获取客户端信息
        // 2. 将文件描述符设置为非阻塞
        // 3. 将新文件描述符加入到epoll模型中
        // 4. 将新文件描述符与啊哈希表建立映射关系

        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        int newfd = accept(con_ptr->Get_fd(), (sockaddr *)&client, &len);
        if (newfd < 0)
        {
            Log(Warning) << "accept fail";
        }
        else
        {
            SetNonBlock(newfd);
            _epoll_ptr->add(newfd, EPOLLIN | EPOLLET);
            _connects.emplace(newfd,
                              std::make_shared<Connection>(newfd, shared_from_this(),
                                                           std::bind(&Loop_Epollserver::Recv, this, std::placeholders::_1),
                                                           std::bind(&Loop_Epollserver::Send, this, std::placeholders::_1),
                                                           nullptr));
            Log(Info) << "accept sucess , fd : " << newfd;
        }
    }

    void Recv(std::shared_ptr<Connection> con_ptr)
    {
        int fd = con_ptr->Get_fd();
        char buffer[1024];
        while (1)
        {
            int n = read(fd, buffer, sizeof(buffer) - 1);
            if (n > 0)
            {
                buffer[n] = 0;
                con_ptr->add_indata(buffer);
            }
            else if (n == 0)
            {
                con_ptr->Get_loopsvr().lock()->Expect(con_ptr);
                return;
            }
            else
            {
                if (errno == EINTR)
                    continue;
                else if (errno == EAGAIN)
                    break;
                else
                {
                    Log(Warning) << "read error";
                    return;
                }
            }
        }

        std::string ret = _OnMessage(con_ptr);
        std::cout << "ret is : " << ret << "\n";
        con_ptr->add_outdata(ret);
        Send(con_ptr);
    }

    void Send(std::shared_ptr<Connection> con_ptr)
    {
        // 将inbuffer中的数据发送出去
        // 1. 循环的往外进行发送
        // 2. 如果发送缓冲区堵塞了,就需要将发送缓冲区添加到等到中

        int fd = con_ptr->Get_fd();
        std::string &outbuffer = con_ptr->Outbuffer();
        while (1)
        {
            int n = write(fd, outbuffer.c_str(), outbuffer.size());
            if (n > 0)
            {
                outbuffer.erase(0, n);
                if (outbuffer.empty())
                    break;
            }
            else if (n == 0)
            {
                con_ptr->Get_loopsvr().lock()->Expect(con_ptr);
                return;
            }
            else
            {
                if (errno == EINTR)
                    continue;
                else if (errno == EAGAIN)
                    break;
                else
                {
                    Log(Warning) << "write error";
                    return;
                }
            }
        }

        if (outbuffer.empty())
        {
            // 进行修改
            // 将写从epoll中移除
            _epoll_ptr->mod(fd, EPOLLIN | EPOLLET);
        }
        else
        {
            // 将写添加到epoll中
            _epoll_ptr->mod(fd, EPOLLIN | EPOLLOUT | EPOLLET);
        }
    }

    void Expect(std::shared_ptr<Connection> con_ptr)
    {
        // 1. 将文件描述符从epoll模型中移除
        // 2. 关闭文件描述符
        // 3. 将con_ptr从哈希表中移除
        int fd = con_ptr->Get_fd();
        _epoll_ptr->del(fd);
        close(fd);
        _connects.erase(fd);
        _delq.push(fd);
    }

    void dispatcher(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int fd = _event_array[i].data.fd;
            uint32_t events = _event_array[i].events;

            if (events & EPOLLERR)
                events |= (EPOLLIN | EPOLLOUT);
            if (events & EPOLLHUP)
                events |= (EPOLLIN | EPOLLOUT);

            if ((events & EPOLLIN) && _connects.count(fd))
            {
                if (_connects[fd]->_recv)
                {
                    _connects[fd]->_recv(_connects[fd]);
                }
            }
            if ((events & EPOLLOUT) && _connects.count(fd))
            {
                std::cout << "da22222222222";
                if (_connects[fd]->_sender)
                {
                    _connects[fd]->_sender(_connects[fd]);
                }
            }
        }
    }

    void Run()
    {
        // 运行
        while (1)
        {
            int n = _epoll_ptr->wait(_event_array, array_num_max, -1);
            if (n > 0)
            {
                // 进行处理
                dispatcher(n);
                // Print();
            }
            else if (n == 0)
            {
                Log(Info) << "I am waiting for you";
            }
            else
            {
                Log(Warning) << "epoll wait error";
            }
        }
    }

    void Print()
    {
        std::cout << "all fd : ";
        for (auto &[fd, ptr] : _connects)
        {
            std::cout << fd << " : " << ptr.use_count() << "\n";
        }
        std::cout << "\n";
    }

private:
    uint16_t _port;
    std::shared_ptr<Sock> _sock_ptr;
    std::shared_ptr<Epoll> _epoll_ptr;

    std::unordered_map<int, std::shared_ptr<Connection>> _connects;
    struct epoll_event _event_array[array_num_max];

    func_t _OnMessage;
    std::queue<int> _delq;
};